package a15;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

/**
 两个切面概念:

 aspect =
 通知1(advice) +  切点1(pointcut)
 通知2(advice) +  切点2(pointcut)
 通知3(advice) +  切点3(pointcut)
 ......


 advisor = 更细粒度的切面，包含一个通知和切点(这个更接近底层)

 */
public class A15 {

    public static void main(String[] args) {
        //1.备好切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");

        //2.备好通知
        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };

        //3.切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);

        /**
         * JDK动态代理和Cglib动态代理在spring中都有使用，那spring怎么决定用那种呢
         *  a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现
         *  b. proxyTargetClass = false,  目标没有实现接口, 用 cglib 实现
         *  c. proxyTargetClass = true, 总是使用 cglib 实现
         */
        ProxyFactory proxyFactory = new ProxyFactory();
        Target1 target1 = new Target1();
        proxyFactory.setTarget(target1);
        proxyFactory.addAdvisor(advisor);
        proxyFactory.setProxyTargetClass(false);
        proxyFactory.setInterfaces(target1.getClass().getInterfaces()); //需要指定接口JDK代理才知道
        I1 proxy = ((I1) proxyFactory.getProxy());
        System.out.println(proxy.getClass());
        proxy.foo();
        proxy.bar();
    }

    interface I1 {
        void foo();

        void bar();
    }

    static class Target1 implements I1 {
        public void foo() {
            System.out.println("target1 foo");
        }

        public void bar() {
            System.out.println("target1 bar");
        }
    }

    static class Target2 {
        public void foo() {
            System.out.println("target2 foo");
        }

        public void bar() {
            System.out.println("target2 bar");
        }
    }
}
